package com.lsj.config.cas;

import com.lsj.config.properties.CasClientProperties;
import com.lsj.config.properties.CasServerProperties;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;

@Configuration
public class CasConfig {

    @Autowired
    CasClientProperties casClientProperties;//配置类
    @Autowired
    CasServerProperties casServerProperties;//配置类
    @Autowired
    UserDetailsService userDetailsService;

    /*CasAuthenticationEntryPoint 则是 CAS 验证的入口*/
    @Bean
    @Primary
    AuthenticationEntryPoint authenticationEntryPoint(){
        CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint();
        //设置cas的登录地址
        entryPoint.setLoginUrl(casServerProperties.getLogin());

        //设置serviceProperties，设置serviceProperties设置了客户端的回调地址，当它登录成功后，就知道往哪里跳转了。
        entryPoint.setServiceProperties(serviceProperties());
        return entryPoint;
    }


    /*CAS 认证的过滤器，过滤器将请求拦截下来之后，交由 CasAuthenticationProvider 来做具体处理。*/
    @Bean
    CasAuthenticationFilter casAuthenticationFilter(){
        CasAuthenticationFilter filter = new CasAuthenticationFilter();
        filter.setServiceProperties(serviceProperties());
        filter.setAuthenticationManager(new ProviderManager(casAuthenticationProvider()));
        return filter;
    }

    /*CasAuthenticationProvider 主要用来处理 CAS 验证逻辑*/
    @Bean
    CasAuthenticationProvider casAuthenticationProvider(){
        CasAuthenticationProvider provider = new CasAuthenticationProvider();
        provider.setServiceProperties(serviceProperties());
        provider.setTicketValidator(ticketValidator());

        //此处设置的userDetailsService的作用并不是用于登录时查询做登录校验的
        //而是在CAS Server登录成功后，CAS client还是要获取用户的基本信息、角色权限等数据，以便进一步做权限控制
        //从CAS Server登录成功后获取到的用户名，作为userDetailsService.loadUserByName的入参，来获取对应的用户基本信息、权限信息等数据
        provider.setUserDetailsService(userDetailsService);
        provider.setKey("lsj");
        return provider;
    }

    /*TicketValidator 这是配置 ticket 校验地址，
    CAS Client 拿到 ticket 要去 CAS Server 上校验，
    默认校验地址是：https://cas.lsj.org:8443/cas/proxyValidate?ticket=xxx
    其中域名是自定定义的，我这里是写在本地的host文件中，指向本机的cas Server*/
    @Bean
    TicketValidator ticketValidator(){
        return new Cas20ProxyTicketValidator(casServerProperties.getPrefix());
    }

    /*ServiceProperties 中主要配置一下 Client 的登录地址即可，
    这个地址就是在 CAS Server 上登录成功后，重定向的地址*/
    @Bean
    ServiceProperties serviceProperties(){
        ServiceProperties serviceProperties = new ServiceProperties();
        serviceProperties.setService(casClientProperties.getLogin());
        return serviceProperties;
    }

    /*SingleSignOutFilter 表示接受 CAS Server 发出的注销请求，
    所有的注销请求都将从 CAS Client 转发到 CAS Server，CAS Server 处理完后，会通知所有的 CAS Client 注销登录。*/
    @Bean
    SingleSignOutFilter singleSignOutFilter(){
        SingleSignOutFilter sign = new SingleSignOutFilter();
        sign.setIgnoreInitConfiguration(true);
        return sign;
    }

    /*LogoutFilter 则是配置将注销请求转发到 CAS Server*/
    @Bean
    LogoutFilter logoutFilter(){
        LogoutFilter filter = new LogoutFilter(casServerProperties.getLogout(),new SecurityContextLogoutHandler());
        filter.setFilterProcessesUrl(casClientProperties.getLogoutRelative());
        return filter;
    }


}
